home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 7 / Apprentice-Release7.iso / Source Code / PowerPlant / Window Utilities / UWindowStagger.cp < prev    next >
Encoding:
Text File  |  1997-01-31  |  12.9 KB  |  354 lines  |  [TEXT/R*ch]

  1. // ===========================================================================
  2. //    File:                        UWindowStagger.cp
  3. // Version:                    1.0.1 - Jan 31, 1997
  4. //    Author:                    Mike Shields (mshields@inconnect.com)
  5. //                            
  6. //    Copyright ©1996 Mike Shields. All rights reserved.
  7. //    I hereby grant users of UWindowStagger permission to use it (or any modified 
  8. //    version of it) in applications (or any other type of Macintosh software 
  9. //    like extensions -- freeware, shareware, commercial, or other) for free, 
  10. //    subject to the terms that:
  11. //
  12. //        (1)  This agreement is non-exclusive.
  13. //
  14. //        (2)  I, Mike Shields, retain the copyright to the original source code.
  15. //
  16. //    These two items are the only required conditions for use. However, I do have 
  17. //    an additional request. Note, however, that this is only a request, and 
  18. //    that it is not a required condition for use of this code.
  19. //
  20. //        (1) That I be given credit for UWindowStagger code in the copyrights or 
  21. //            acknowledgements section of your manual or other appropriate documentation.
  22. //
  23. //
  24. //    I would like to repeat that this last item is only a request. You are prefectly 
  25. //    free to choose not to do any or all of them.
  26. //    
  27. //        This source code is distributed in the hope that it will be useful,
  28. //        but WITHOUT ANY WARRANTY; without even the implied warranty of
  29. //        MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  30. // ===========================================================================
  31. //    UWindowStagger.h        <- double-click + Command-D to see class declaration
  32. //
  33. // Static class which allows you to stagger windows on the desktop in an intelligent
  34. // manner.
  35.  
  36. #include "UWindowStagger.h"
  37.  
  38. #include <LWindow.h>
  39. #include <UWindows.h>
  40.  
  41. //---------------------------------------------------------------------------
  42. // UWindowStagger::StaggerFromPosition()
  43. //---------------------------------------------------------------------------
  44. // This function places a window at a position which no other window occupies, 
  45. // starting with the position passed in. If the calculated position is full, 
  46. // we continue to offset until we find an open space.  If the space we end up 
  47. // with does not allow the window to fit entirely on one monitor, we start 
  48. // again at the upper left-hand corner of the monitor.
  49. void UWindowStagger::StaggerFromPosition(LWindow* inWindow, Point inPosition, 
  50.                                                         short inDeltaH, short inDeltaV)
  51. {
  52.     Point            topLeftPosition;
  53.     Rect            monitorRect;
  54.     Point            newPosition = inPosition;
  55.     
  56.     // take into account the menu bar when determining where to put the first
  57.     // window
  58.     topLeftPosition.h = 4;
  59.     topLeftPosition.v = 22 + LMGetMBarHeight();
  60.     
  61.     UWindowStagger::GetMonitorRect(inWindow->GetMacPort(), monitorRect);
  62.  
  63.     // check to see if we are not on the main screen. if that's the case, we need to
  64.     // fix ourselves to NOT use the menubar height.
  65.     if ( topLeft(monitorRect).v != 0  ) 
  66.     {
  67.         topLeftPosition.v += topLeft(monitorRect).v;
  68.         topLeftPosition.v -= LMGetMBarHeight();
  69.     }
  70.     if ( topLeft(monitorRect).h != 0  ) 
  71.     {
  72.         topLeftPosition.h += topLeft(monitorRect).h;
  73.     }
  74.  
  75.     Point    delta;
  76.     delta.h = inDeltaH;
  77.     delta.v = inDeltaV;
  78.     UWindowStagger::MakePositionUnique(inWindow, newPosition, topLeftPosition, 
  79.                                                     delta, monitorRect);
  80.     inWindow->DoSetPosition(newPosition);
  81. }
  82.  
  83. //---------------------------------------------------------------------------
  84. // UWindowStagger::Stagger()
  85. //---------------------------------------------------------------------------
  86. // Here, every window is, by default, offset from the position
  87. // of the window behind it.  If the calculated position is full, we continue 
  88. // to offset until we find an open space.  If the space we end up with does not 
  89. // allow the window to fit entirely on one monitor, we start again at the upper 
  90. // left-hand corner of the monitor.
  91. void UWindowStagger::Stagger(LWindow* inWindow, short inDeltaH, short inDeltaV)
  92. {
  93.     Point            topLeftPosition;
  94.     Point            newPosition;
  95.     LWindow*        frontWindow;
  96.     Rect            temp;
  97.     Rect            monitorRect;
  98.     Point            localTopLeft;
  99.     
  100.     // take into account the menu bar when determining where to put the first
  101.     // window
  102.     topLeftPosition.h = 4;
  103.     topLeftPosition.v = 22 + LMGetMBarHeight();
  104.         
  105.     // find the front window and take note of its monitor rectangle
  106.     frontWindow = UDesktop::FetchTopRegular();
  107.     UWindowStagger::GetMonitorRect(frontWindow->GetMacPort(), monitorRect);
  108.     
  109.     if ( frontWindow == NULL ) 
  110.     {
  111.         // if there is no front window, the new window will go in the upper left-hand
  112.         // corner of the main monitor, defined above
  113.         newPosition = topLeftPosition;
  114.         localTopLeft = topLeftPosition;
  115.     }
  116.     else 
  117.     {
  118.         // if there is a front window, the new one will be offset from it by the
  119.         // value of "delta" and the upper left-hand corner we use for positioning
  120.         // will be that of the monitor containing the most of the current front
  121.         // window (notice we have to adjust for the menu bar size)
  122.         temp = UWindows::GetWindowContentRect(frontWindow->GetMacPort());
  123.         newPosition = topLeft(temp);
  124.         newPosition.h += inDeltaH;
  125.         newPosition.v += inDeltaV;
  126.         localTopLeft = topLeftPosition;
  127.         if ( topLeft(monitorRect).v != 0  ) 
  128.         {
  129.             localTopLeft.v += topLeft(monitorRect).v;
  130.             localTopLeft.v -= LMGetMBarHeight();
  131.         }
  132.         if ( topLeft(monitorRect).h != 0  ) 
  133.         {
  134.             localTopLeft.h += topLeft(monitorRect).h;
  135.         }
  136.     }
  137.     
  138.     Point    delta;
  139.     delta.h = inDeltaH;
  140.     delta.v = inDeltaV;
  141.     UWindowStagger::MakePositionUnique(inWindow, newPosition, localTopLeft, 
  142.                                                     delta, monitorRect);
  143.     inWindow->DoSetPosition(newPosition);
  144. }
  145.  
  146.  
  147. //---------------------------------------------------------------------------
  148. // MakePositionUnique
  149. //---------------------------------------------------------------------------
  150. // Find a position for the window which is not occupied by any other window
  151. void UWindowStagger::MakePositionUnique(LWindow* inWindow, Point &inNewPosition, 
  152.                                                     Point inTopLeft, Point inDelta, 
  153.                                                     const Rect& inMonitorRect)
  154. {
  155.     Point            workPosition = inNewPosition;
  156.     Point            tempTopLeft;
  157.     
  158.     // for as long as the proposed position is on the screen and another window
  159.     // occupies this position, keep advancing down and to the right until we
  160.     // either march off the screen or find an unoccupied position
  161.     while ( ::PtInRect(workPosition, &inMonitorRect) && 
  162.                 !UWindowStagger::IsPositionUnique(workPosition) )
  163.     {
  164.         workPosition.h += inDelta.h;
  165.         workPosition.v += inDelta.v;
  166.     }
  167.     
  168.     // if we've marched off the screen or if the unoccupied position won't
  169.     // allow the whole window to be on the screen, try again starting at the
  170.     // monitor's upper left-hand corner
  171.     if ( !::PtInRect(workPosition, &inMonitorRect) || 
  172.             !UWindowStagger::WillWindowFit(inWindow, workPosition, inMonitorRect) ) 
  173.     {
  174.         if ( inNewPosition.v != inTopLeft.v || inNewPosition.h != inTopLeft.h ) 
  175.         {
  176.             workPosition = inTopLeft;
  177.             if ( !UWindowStagger::IsPositionUnique(workPosition) ) 
  178.             {
  179.                 UWindowStagger::MakePositionUnique(inWindow, workPosition, inTopLeft, 
  180.                                                                 inDelta, inMonitorRect);
  181.                 
  182.                 // if we can't find an unoccupied position that will hold the
  183.                 // window after starting at the upper left-hand corner of the
  184.                 // monitor, try again, but start halfway between the first two
  185.                 // window positions on the monitor (the test here causes
  186.                 // recursive calls to fall out if they don't find an acceptable
  187.                 // position)
  188.                 if ( workPosition.v == inTopLeft.v && workPosition.h == inTopLeft.h ) 
  189.                 {
  190.                     workPosition.h += inDelta.h / 2;
  191.                     workPosition.v += inDelta.v / 2;
  192.                     
  193.                     if ( !UWindowStagger::IsPositionUnique(workPosition) ) 
  194.                     {
  195.                         tempTopLeft = workPosition;
  196.                         UWindowStagger::MakePositionUnique(inWindow, workPosition, tempTopLeft, 
  197.                                                                         inDelta, inMonitorRect);
  198.                         
  199.                         // if that doesn't work either, give up and just put the
  200.                         // window in the upper left-hand corner of the monitor
  201.                         if ( workPosition.v == tempTopLeft.v && workPosition.h == tempTopLeft.h )
  202.                             workPosition = inTopLeft;
  203.                     }
  204.                 }
  205.             }
  206.         }
  207.         else
  208.             workPosition = inNewPosition;
  209.     }
  210.     
  211.     // return the new position
  212.     inNewPosition = workPosition;
  213. }
  214.  
  215. //---------------------------------------------------------------------------
  216. // WillWindowFit()
  217. //---------------------------------------------------------------------------
  218. // determines whether the window will fit entirely within the specified monitorRect 
  219. // if its upper left-hand corner is placed at "pos".  Returns true if the window will 
  220. // fit there, and false if it won't.
  221. Boolean UWindowStagger::WillWindowFit(LWindow* inWindow, Point inCurrentPosition, 
  222.                                                 const Rect& inMonitorRect)
  223. {
  224.     Point                windowBotRight;
  225.     SDimension16    frameSize;
  226.         
  227.     // the insetting here takes into account the frame and drop shadow (we don't
  228.     // care about the title bar, since we're always going down and to the right
  229.     // and we know we started in a position where the title bar will work)
  230.     inWindow->GetFrameSize(frameSize);
  231.     windowBotRight.h = inCurrentPosition.h + frameSize.width - 2;
  232.     windowBotRight.v = inCurrentPosition.v + frameSize.height - 2;
  233.     
  234.     return ::PtInRect(windowBotRight, &inMonitorRect);
  235. }
  236.  
  237. //---------------------------------------------------------------------------
  238. // IsPositionUnique
  239. //---------------------------------------------------------------------------
  240. // Returns true if no currently visible window in the Window Manager's window list 
  241. // has its upper left-hand corner at the position specified by "pos".
  242. Boolean UWindowStagger::IsPositionUnique(Point inPosition)
  243. {
  244.     WindowPtr        aWindowPtr;
  245.     Rect                windowRect;
  246.  
  247.     for ( short i = 1; (aWindowPtr = UWindows::FindNthWindow(i)) != nil; i++ )
  248.     {
  249.         LWindow    *aWindow = LWindow::FetchWindowObject(aWindowPtr);
  250.  
  251.         // We only want to check visible and "normal" windows. No floating windows
  252.         // should be checked against.
  253.         if ( aWindow->IsVisible() && aWindow->HasAttribute(windAttr_Regular) ) 
  254.         {
  255.             windowRect = UWindows::GetWindowContentRect(aWindowPtr);
  256.             if ( topLeft(windowRect).h == inPosition.h && topLeft(windowRect).v == inPosition.v  )
  257.                 return false;
  258.         }
  259.     }
  260.     return true;
  261. }
  262.  
  263. //---------------------------------------------------------------------------
  264. // UWindowStagger::ForceOnScreen
  265. //---------------------------------------------------------------------------
  266. // Forces the window to be completely visible on the screen
  267. void UWindowStagger::ForceOnScreen(LWindow* inWindow)
  268. {
  269.     Rect                monitorRect;
  270.     Point                windowBotRight = {0, 0};
  271.     SDimension16    frameSize;
  272.     
  273.     UWindowStagger::GetMonitorRect(inWindow->GetMacPort(), monitorRect);
  274.  
  275.     // Calculate the bottom right edge of the window.
  276.     inWindow->PortToGlobalPoint(windowBotRight);
  277.     inWindow->GetFrameSize(frameSize);
  278.     windowBotRight.h += frameSize.width;
  279.     windowBotRight.v += frameSize.height;
  280.     
  281.     if ( !::PtInRect(windowBotRight, &monitorRect) )
  282.     {
  283.         // the bottom right edge is off the screen, we need to adjust.
  284.         
  285.         Rect        currBounds = UWindows::GetWindowContentRect(inWindow->GetMacPort());
  286.         
  287.         // First position the window so it's bottom right corner is on the screen.
  288.         if ( windowBotRight.v > monitorRect.bottom )
  289.         {
  290.             currBounds.top -= (windowBotRight.v - monitorRect.bottom);
  291.             currBounds.bottom -= (windowBotRight.v - monitorRect.bottom);
  292.         }
  293.         
  294.         if ( windowBotRight.h > monitorRect.right )
  295.         {
  296.             currBounds.left -= (windowBotRight.h - monitorRect.right);;
  297.             currBounds.right -= (windowBotRight.h - monitorRect.right);;
  298.         }
  299.         
  300.         // now check to see if that makes the window's top, left go off the screen.
  301.         // if that's the case, the window is simply too big to fit, so we make it
  302.         // exactly the size of the monitor. We also check to see if we're on the main
  303.         // screen (or not on any screen) and take into account the menu bar in that case.
  304.         // We could also be nice and if we are on the main monitor, we could take off some
  305.         // width for the disk icons, but for now we won't
  306.         if ( currBounds.top < monitorRect.top )
  307.         {
  308.             if ( topLeft(monitorRect).v == 0  ) 
  309.                 currBounds.top = monitorRect.top + LMGetMBarHeight() + 22;
  310.             else
  311.                 currBounds.top = monitorRect.top + 22;
  312.             
  313.             currBounds.bottom = monitorRect.bottom;
  314.         }
  315.         
  316.         if ( currBounds.left < monitorRect.left )
  317.         {
  318.             currBounds.left = monitorRect.left;
  319.             currBounds.right = monitorRect.right;
  320.         }
  321.         
  322.         inWindow->DoSetBounds(currBounds);
  323.     }
  324. }
  325.  
  326. //---------------------------------------------------------------------------
  327. // UWindowStagger::GetMonitorRect
  328. //---------------------------------------------------------------------------
  329. // Determines which monitor contains the greatest portion of the passed in window
  330. // and returns the rect describing that device
  331. void UWindowStagger::GetMonitorRect(WindowPtr inWindow, Rect& outMonitorRect)
  332. {
  333.     GDHandle        monitor;
  334.     
  335.     if ( inWindow == NULL ) 
  336.     {
  337.         // if there are no open windows, use the main monitor
  338.         monitor = GetMainDevice();
  339.     }
  340.     else
  341.     {
  342.         // otherwise, find out which monitor contains the most of the frontmost 
  343.         // window and then get info for it
  344.         monitor = UWindows::FindDominantDevice(UWindows::GetWindowContentRect(inWindow));
  345.         if ( monitor == NULL )
  346.         {
  347.             // This window isn't on ANY monitor, so just use the main one.
  348.             monitor = GetMainDevice();
  349.         }
  350.     }
  351.     SignalIfNot_(monitor);
  352.     outMonitorRect = (**monitor).gdRect;
  353. }
  354.